////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


#ifndef __WN_CALLBACK_JOBS_H__
#define __WN_CALLBACK_JOBS_H__

#include "WNConcurrency/inc/WNThreadJob.h"
#include "WNContainers/inc/WNCallback.h"
namespace WNConcurrency {

template<typename T>
    class WNCallbackJob0 : public WNThreadJob {
    public:
        WNCallbackJob0(const WNContainers::WNCallback0<T>& _callback):
            mCallback(_callback) {
        }
        virtual ~WNCallbackJob0() {
        }
        virtual WN_VOID Execute() {
            mResult = mCallback.Execute();
        }
        const T& GetResult() {
            return(mResult);
        }
    private:
        WNContainers::WNCallback0<T> mCallback;
        T mResult;
    };

    template<>
    class WNCallbackJob0<WN_VOID> : public WNThreadJob {
    public:
        WNCallbackJob0(const WNContainers::WNCallback0<WN_VOID>& _callback) :
            mCallback(_callback){
        }
        virtual ~WNCallbackJob0() {
        }
        virtual WN_VOID Execute() {
            mCallback.Execute();
        }
    private:
        WNContainers::WNCallback0<WN_VOID> mCallback;
    };

    template<typename T, typename P1>
    class WNCallbackJob1 : public WNThreadJob {
    public:
        WNCallbackJob1(const WNContainers::WNCallback1<T, P1>& _callback, const P1& _val1):
            mCallback(_callback),
            mP1Val(_val1)
        {
        }
        virtual ~WNCallbackJob1() {
        }
        virtual WN_VOID Execute() {
            mResult = mCallback.Execute(mP1Val);
        }
        const T& GetResult() {
            return(mResult);
        }
    private:
        WNContainers::WNCallback1<T, P1> mCallback;
        P1 mP1Val;
        T mResult;
    };

    template<typename P1>
    class WNCallbackJob1<WN_VOID, P1> : public WNThreadJob {
    public:
        WNCallbackJob1(const WNContainers::WNCallback1<WN_VOID, P1>& _callback, const P1& _val1):
            mCallback(_callback),
            mP1Val(_val1)
        {
        }
        virtual ~WNCallbackJob1() {
        }
        virtual WN_VOID Execute() {
            mCallback.Execute(mP1Val);
        }
    private:
        WNContainers::WNCallback1<WN_VOID, P1> mCallback;
        P1 mP1Val;
    };

    template<typename T, typename P1, typename P2>
    class WNCallbackJob2 : public WNThreadJob {
    public:
        WNCallbackJob2(const WNContainers::WNCallback2<T, P1, P2>& _callback, const P1& _val1, const P2& _val2):
            mCallback(_callback),
            mP1Val(_val1),
            mP2Val(_val2)
        {
        }
        virtual ~WNCallbackJob2() {
        }
        virtual WN_VOID Execute() {
            mResult = mCallback.Execute(mP1Val, mP2Val);
        }
        const T& GetResult() {
            return(mResult);
        }
    private:
        WNContainers::WNCallback2<T, P1, P2> mCallback;
        P1 mP1Val;
        P2 mP2Val;
        T mResult;
    };

    template<typename P1, typename P2>
    class WNCallbackJob2<WN_VOID, P1, P2> : public WNThreadJob {
    public:
        WNCallbackJob2(const WNContainers::WNCallback2<WN_VOID, P1, P2>& _callback, const P1& _val1, const P2& _val2):
            mCallback(_callback),
            mP1Val(_val1),
            mP2Val(_val2)
        {
        }
        virtual ~WNCallbackJob2() {
        }
        virtual WN_VOID Execute() {
            mCallback.Execute(mP1Val, mP2Val);
        }
    private:
        WNContainers::WNCallback2<WN_VOID, P1, P2> mCallback;
        P1 mP1Val;
        P2 mP2Val;
    };

    template<typename T, typename P1, typename P2, typename P3>
    class WNCallbackJob3 : public WNThreadJob {
    public:
        WNCallbackJob3(const WNContainers::WNCallback3<T, P1, P2, P3>& _callback, const P1& _val1, const P2& _val2, const P3& _val3):
            mCallback(_callback),
            mP1Val(_val1),
            mP2Val(_val2),
            mP3Val(_val3)
        {
        }
        virtual ~WNCallbackJob3() {
        }
        virtual WN_VOID Execute() {
            mResult = mCallback.Execute(mP1Val, mP2Val);
        }
        const T& GetResult() {
            return(mResult);
        }
    private:
        WNContainers::WNCallback3<T, P1, P2, P3> mCallback;
        P1 mP1Val;
        P2 mP2Val;
        P3 mP3Val;
        T mResult;
    };

    template<typename P1, typename P2, typename P3>
    class WNCallbackJob3<WN_VOID, P1, P2, P3> : public WNThreadJob {
    public:
        WNCallbackJob3(const WNContainers::WNCallback3<WN_VOID, P1, P2, P3>& _callback, const P1& _val1, const P2& _val2, const P3& _val3):
            mCallback(_callback),
            mP1Val(_val1),
            mP2Val(_val2),
            mP3Val(_val3)
        {
        }
        virtual ~WNCallbackJob3() {
        }
        virtual WN_VOID Execute() {
            mCallback.Execute(mP1Val, mP2Val, mP3Val);
        }
    private:
        WNContainers::WNCallback3<WN_VOID, P1, P2, P3> mCallback;
        P1 mP1Val;
        P2 mP2Val;
        P3 mP3Val;
    };
}



template <typename Ret>
WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob0<Ret> > WNAllocateCJob(Ret (*_ptr)()) {
    return(WNContainers::WNAllocateResource1<WNConcurrency::WNCallbackJob0<Ret> >(WNContainers::WNCallback0<Ret>(_ptr)));
}
template <typename Ret, typename C>
WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob0<Ret> > WNAllocateCJob(Ret (C::*_ptr)(), C* _this) {
    return(WNContainers::WNAllocateResource1<WNConcurrency::WNCallbackJob0<Ret> >(WNContainers::WNCallback0<Ret>(_this, _ptr)));
}
template <typename Ret, typename P1>
WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob1<Ret, P1> > WNAllocateCJob(Ret (*_ptr)(P1), P1 _param) {
    return(WNContainers::WNAllocateResource2<WNConcurrency::WNCallbackJob1<Ret, P1> >(WNContainers::WNCallback1<Ret, P1>(_ptr), _param));
}
template <typename Ret, typename C, typename P1>
WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob1<Ret, P1> > WNAllocateCJob(Ret (C::*_ptr)(P1), C*_this, P1 _param) {
    return(WNContainers::WNAllocateResource2<WNConcurrency::WNCallbackJob1<Ret, P1> >(WNContainers::WNCallback1<Ret, P1>(_this, _ptr), _param));
}

template <typename Ret, typename P1, typename P2>
WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob2<Ret, P1, P2> > WNAllocateCJob(Ret (*_ptr)(P1, P2), P1 _param, P2 _param2) {
    return(WNContainers::WNAllocateResource3<WNConcurrency::WNCallbackJob2<Ret, P1, P2> >(WNContainers::WNCallback2<Ret, P1, P2>(_ptr), _param, _param2));
}
template <typename Ret, typename C, typename P1, typename P2>
WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob2<Ret, P1, P2> > WNAllocateCJob(Ret (C::*_ptr)(P1, P2), C*_this, P1 _param, P2 _param2) {
    return(WNContainers::WNAllocateResource3<WNConcurrency::WNCallbackJob2<Ret, P1, P2> >(WNContainers::WNCallback2<Ret, P1, P2>(_this, _ptr), _param, _param2));
}

template <typename Ret, typename P1, typename P2, typename P3>
WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob3<Ret, P1, P2, P3> > WNAllocateCJob(Ret (*_ptr)(P1, P2, P3), P1 _param, P2 _param2, P3 _param3) {
    return(WNContainers::WNAllocateResource4<WNConcurrency::WNCallbackJob3<Ret, P1, P2, P3> >(WNContainers::WNCallback3<Ret, P1, P2, P3>(_ptr), _param, _param2, _param3));
}
template <typename Ret, typename C, typename P1, typename P2, typename P3>
WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob3<Ret, P1, P2, P3> > WNAllocateCJob(Ret (C::*_ptr)(P1, P2, P3), C*_this, P1 _param, P2 _param2, P3 _param3) {
    return(WNContainers::WNAllocateResource4<WNConcurrency::WNCallbackJob3<Ret, P1, P2, P3> >(WNContainers::WNCallback3<Ret, P1, P2, P3>(_this, _ptr), _param, _param2, _param3));
}

#define CREATE_CBJOB_TYPEDEF0(name, T) typedef WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob0<T> > name 
#define CREATE_CBJOB_TYPEDEF1(name, T, T2) typedef WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob1<T, T2> > name 
#define CREATE_CBJOB_TYPEDEF2(name, T, T2, T3) typedef WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob2<T, T2, T3> > name 
#define CREATE_CBJOB_TYPEDEF3(name, T, T2, T3, T4) typedef WNContainers::WNResourcePointer<WNConcurrency::WNCallbackJob3<T, T2, T3, T4> > name 


#endif//__WN_THREAD_JOB_H__